#pragma once

#include<iostream>
#include<cstdio>
#include<sys/types.h>
#include<sys/ipc.h>
#include<cerrno>
#include<cstring>
#include<cstdlib>
#include<sys/shm.h>
#include<unistd.h>


using namespace std;

#define PathName "/root/110" //在文件系统中存在的文件路径
#define Proj_Id 125 
#define Size 4096 //共享内存大小,通常以4kb为基本单位,建议申请的大小为4kb的整数倍

const string ToHex(key_t key) //将整数转化为十六进制
{
    char buffer[256];
    snprintf(buffer, sizeof(buffer), "0x%x", key);
    return buffer;
}

key_t GetShmKeyorDie() //获取key值
{   
    int key = ftok(PathName, Proj_Id);
    if(key == -1) 
    {
        cerr << "ftok failed, errno: " << errno << "error reason: " << strerror(errno) << endl;
        exit(1);
    }
    return key;
}

int CreatShmorDie(key_t key, int size, int flag) //1.创建共享内存
{
    int shmid = shmget(key, size, flag);
    if(shmid == -1)
    {
        cerr << "shmget failed, errno: " << errno << "error reason: " << strerror(errno) << endl;
        exit(2);
    }
    return shmid; //共享内存的标识符
}

//Tips:使用共享内存通信,一定是一个进程创建新的共享内存,另一个进程直接获取共享内存
int CreatShm(key_t key)  //服务端,创建共享内存
{
    return CreatShmorDie(key, Size, IPC_CREAT|IPC_EXCL|0666);
}

int GetShm(key_t key) //客户端,使用共享内存
{
    return CreatShmorDie(key, Size, IPC_CREAT);
}

void* AttShm(int shmid) //2.进程挂接共享内存,构建映射
{
    void* addr = shmat(shmid, nullptr, 0); //shmaddr为null,由OS自动生成虚拟地址
    if(addr == NULL)
    {
        cerr << "shmat failed, errno: " << errno << "error reason: " << strerror(errno) << endl;
        return nullptr;
    }
    return addr;
}

void DetachShm(void* addr) //4.断开共享内存的连接,解除映射
{
    int n = shmdt(addr); 
    if(n == -1)
        cerr << "shmdt failed, errno: " << errno << "error reason: " << strerror(errno) << endl;
}

void DelShm(int shmid) //5.删除共享内存
{
    int n = shmctl(shmid, IPC_RMID, nullptr);
    if(n == -1)
        cerr << "shmctl failed, errno: " << errno << "error reason: " << strerror(errno) << endl;
    else
        cout << "shmctl delete success!" << endl;
}

void ShmDebug(int shmid)  //获取共享内存的属性信息
{
    struct shmid_ds shmds; 
    int n = shmctl(shmid, IPC_STAT, &shmds);
    if(n == -1)
        cerr << "shmctl failed, errno: " << errno << "error reason: " << strerror(errno) << endl;
    else
    {
        cout << "nattch" << shmds.shm_nattch << endl;
        cout << "key" << shmds.shm_perm.__key << endl;
        cout << "attch time" << shmds.shm_atime << endl;
        cout << "detach time" << shmds.shm_dtime << endl;
    }
}

